package com.example.demo.services;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.demo.config.RedisTemplateBean;
import com.example.demo.model.ArticleModel;
import com.example.demo.model.CategoryModel;
import com.example.demo.dao.CategoryDao;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;
import java.util.List;

@Service
public class CategoryService {

    @Resource
    CategoryDao categoryDao;
    @Resource
    RedisTemplateBean redisTemplateBean;

    /**
     * 获取文章分类列表，默认从缓存获取
     * @return
     */
    public List<CategoryModel> getCategoryList(){
        RedisTemplate redisTemplate = redisTemplateBean.redisTemplate();
        // 缓存Key
        String categoryListCacheKey = "categoryList";
        // 缓存时间
        int categoryListCacheExpire = 3600 * 24 * 7;
        // 如果缓存存在则使用缓存
        if (redisTemplate.hasKey(categoryListCacheKey)) {
            return getCategoryListToCache(categoryListCacheKey);
        } else {
            // 防止并发写入，加锁
            if (redisTemplate.opsForValue().setIfAbsent("categoryListCacheLock", 1)) {
                // 设置过期时间2秒
                redisTemplate.expire("categoryListCacheLock", 2000, TimeUnit.SECONDS);
                // 从DB获取
                List<CategoryModel> categoryDataList = categoryDao.getCategoryList();
                List<String> categoryStringArray = new ArrayList<>();
                for (int i = 0; i < categoryDataList.size(); i++){
                    categoryStringArray.add(JSON.toJSONString(categoryDataList.get(i)));
                }
                // 写入redis缓存
                redisTemplate.opsForList().rightPushAll(categoryListCacheKey, categoryStringArray);
                redisTemplate.expire(categoryListCacheKey, categoryListCacheExpire, TimeUnit.SECONDS);
                // 及时释放锁
                redisTemplate.delete("categoryListCacheLock");
            }

            return getCategoryListToCache(categoryListCacheKey);
        }
    }

    /**
     * 获取以ID为键值的分类列表
     * @return
     */
    public HashMap<Long, CategoryModel> getForIdMapCategoryList() {
        List<CategoryModel> categoryList = getCategoryList();
        HashMap<Long, CategoryModel> forIdMapCategoryList = new HashMap<>();
        for (CategoryModel categoryItem: categoryList) {
            forIdMapCategoryList.put(categoryItem.getId(), categoryItem);
        }
        return forIdMapCategoryList;
    }

    /**
     * 单纯从redis缓存获取章节分类列表（不做缓存是否存在处理）
     * @param cacheKey
     * @return
     */
    private List<CategoryModel> getCategoryListToCache(String cacheKey){
        RedisTemplate redisTemplate = redisTemplateBean.redisTemplate();
        // 从redis获取
        List<String> categoryStringList = redisTemplate.opsForList().range(cacheKey, 0, -1);
        List<CategoryModel> categoryModelList = new ArrayList<>();
        for (int i = 0; i < categoryStringList.size(); i++){
            categoryModelList.add(JSONObject.parseObject(categoryStringList.get(i), CategoryModel.class));
        }

        return categoryModelList;
    }

    public PageInfo getCategoryListFromDb(
            int pageNum,
            int pageSize
    ) {
        PageHelper.startPage(pageNum, pageSize);
        return new PageInfo(getCategoryListFromDb());
    }

    public CategoryModel getCategoryInfo(Long id) {
        return categoryDao.getCategoryInfoById(id);
    }

    /**
     * 获取文章所有列表（包括UV、标签等字段）
     * @return
     */
    public List<CategoryModel> getCategoryListFromDb(){
        return categoryDao.getCategoryList();
    }

    public int add(CategoryModel categoryModel) {
        return categoryDao.addCategory(categoryModel);
    }

    public boolean edit(CategoryModel categoryModel) {
        return categoryDao.updateCategoryById(categoryModel);
    }

    public boolean del(Long id) {
        return categoryDao.del(id);
    }

}
